import ctypes as ctypes
import random

import ogre.renderer.OGRE as og


# class to handle material switching without having to modify scene materials individually
class MaterialSwitcher( og.MaterialManager.Listener ):
    def __init__(self):
        og.MaterialManager.Listener.__init__(self)

        self.currentColor = og.ColourValue(0.0, 0.0, 0.0)
        self.currentColorAsVector3 = og.Vector3()

        self.lastEntity = ""
        self.lastTechnique = None

        self.colorDict = {}

    # takes into account that one Entity can have multiple SubEntities
    def handleSchemeNotFound(self, index, name, material, lod, subEntity):
        temp = str(type(subEntity))
        if temp == "<class 'ogre.renderer.OGRE._ogre_.SubEntity'>":
            if self.lastEntity == subEntity.getParent().getName():
                subEntity.setCustomParameter(1, og.Vector4(self.currentColor.r, self.currentColor.g, self.currentColor.b, 1.0))
                return self.lastTechnique
            else:
                self.lastTechnique = og.MaterialManager.getSingleton().load("PlainColor", og.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME).getTechnique(0)

                self.randomizeColor()
                subEntity.setCustomParameter(1, og.Vector4(self.currentColor.r, self.currentColor.g, self.currentColor.b, 1.0))

                self.lastEntity = subEntity.getParent().getName()
                self.colorDict[self.lastEntity] = self.currentColorAsVector3
                return self.lastTechnique


    def randomizeColor(self):
        r = random.randrange(1, 255)
        g = random.randrange(1, 255)
        b = random.randrange(1, 255)
        self.currentColorAsVector3 = og.Vector3(r, g, b)
        var = 1.0 / 255.0

        self.currentColor = og.ColourValue(r * var, g * var, b * var)

    def reset(self):
        self.currentColor = og.ColourValue(0.0, 0.0, 0.0)
        self.lastEntity = ""

# We need this attached to the depth target, otherwise we get problems with the compositor
# MaterialManager.Listener should NOT be running all the time - rather only when we're
# specifically rendering the target that needs it
class SelectionRenderListener(og.RenderTargetListener):
    def __init__(self, materialListener):
        og.RenderTargetListener.__init__(self)
        self.materialListener = materialListener

    def preRenderTargetUpdate(self, evt):
        og.MaterialManager.getSingleton().addListener( self.materialListener )

    def postRenderTargetUpdate(self, evt):
        og.MaterialManager.getSingleton().removeListener( self.materialListener )


class SelectionBuffer():
    # sceneManager is the ogre.SceneManager wich this buffer belongs to
    # renderTarget is the ogre.RenderTarget in wich you want to select
    def __init__(self, sceneManager,  renderTarget):
        self.sceneMgr = sceneManager
        self.camera = sceneManager.getCamera("PlayCamera")

        self.renderTarget = renderTarget

        # This is the material listener - Note: it is controlled by a seperate
        # RenderTargetListener, not applied globally to all targets
        self.materialSwitchListener = MaterialSwitcher()

        self.selectionTargetListener = SelectionRenderListener( self.materialSwitchListener )

        width = self.renderTarget.getWidth()
        height = self.renderTarget.getHeight()

        self.texture = og.TextureManager.getSingleton().createManual("SelectionPassTex",
                                                                    og.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
                                                                    og.TEX_TYPE_2D,
                                                                    width,
                                                                    height,
                                                                    0, og.PixelFormat.PF_R8G8B8, og.TU_RENDERTARGET)

        self.renderTexture = self.texture.getBuffer().getRenderTarget()
        self.renderTexture.setAutoUpdated(False)
        self.renderTexture.setPriority(0)
        self.renderTexture.addViewport( self.camera )
        self.renderTexture.getViewport(0).setOverlaysEnabled(False)
        self.renderTexture.getViewport(0).setClearEveryFrame(True)
        self.renderTexture.addListener( self.selectionTargetListener )
        self.renderTexture.getViewport(0).setMaterialScheme("aa")

        #self.createRTTOverlays()

    def update(self):
        self.updateBufferSize()

        self.renderTexture.update()
        self.materialSwitchListener.reset()

        pixelBuffer = self.texture.getBuffer()
        bufferSize = pixelBuffer.getSizeInBytes()
        #buffersize2 = self.renderTexture.getWidth()*self.renderTexture.getHeight()*4

        storageclass = ctypes.c_uint8 * (bufferSize)
        self.buffer = storageclass()


        VoidPointer = og.castAsVoidPtr(ctypes.addressof(self.buffer))

        self.pBox = og.PixelBox(pixelBuffer.getWidth(), pixelBuffer.getHeight(),pixelBuffer.getDepth(), pixelBuffer.getFormat(), VoidPointer)
        self.renderTexture.copyContentsToMemory(self.pBox, og.RenderTarget.FrameBuffer.FB_FRONT)


    def updateBufferSize(self):
        width = self.renderTarget.getWidth()
        height = self.renderTarget.getHeight()
        needsSizeUpdate = False

        if width is not self.renderTexture.getWidth():
            needsSizeUpdate = True
        if height is not self.renderTexture.getHeight():
            needsSizeUpdate = True

        if needsSizeUpdate:
            og.TextureManager.getSingleton().unload("SelectionPassTex")

            self.texture = og.TextureManager.getSingleton().createManual("SelectionPassTex",
                                                            og.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
                                                            og.TEX_TYPE_2D,
                                                            width,
                                                            height,
                                                            0, og.PixelFormat.PF_R8G8B8, og.TU_RENDERTARGET)

            self.renderTexture = self.texture.getBuffer().getRenderTarget()
            self.renderTexture.setAutoUpdated(False)
            self.renderTexture.setPriority(0)
            self.renderTexture.addViewport( self.camera )
            self.renderTexture.getViewport(0).setOverlaysEnabled(False)
            self.renderTexture.getViewport(0).setClearEveryFrame(True)
            self.renderTexture.addListener( self.selectionTargetListener )
            self.renderTexture.getViewport(0).setMaterialScheme("aa")
        else:
            return

    def onSelectionClick(self, x, y):
        self.update()

        posInStream = (self.pBox.getWidth() * y - 1)*4
        posInStream += x*4


        colVec = og.Vector3(self.buffer[int(posInStream) + 2], self.buffer[int(posInStream)+1], self.buffer[int(posInStream)])

        for key in self.materialSwitchListener.colorDict:
            if self.materialSwitchListener.colorDict[key] == colVec:
	      return self.sceneMgr.getEntity(key)

        return None

    def createRTTOverlays(self):
        baseWhite = og.MaterialManager.getSingletonPtr().getByName("PlainColor")
        SelectionBufferTexture = baseWhite.clone("SelectionDebugMaterial")
        textureUnit = SelectionBufferTexture.getTechnique(0).getPass(0).createTextureUnitState()

        textureUnit.setTextureName("SelectionPassTex")


        overlayManager = og.OverlayManager.getSingleton()
        # Create an overlay
        self.mDebugOverlay = overlayManager.create("OverlayName")

        # Create a panel
        panel = overlayManager.createOverlayElement("Panel", "PanelName0")
        panel.setMetricsMode(og.GMM_PIXELS)
        panel.setPosition(10, 10)
        panel.setDimensions(400, 280)
        panel.setMaterialName("SelectionDebugMaterial")
        self.mDebugOverlay.add2D(panel)

        self.mDebugOverlay.show()